package com.barbarosso.utils.array {
	import nl.demonsters.debugger.MonsterDebugger;	
	
	/**
	 * @author Administrator
	 */
	public class ArrayCollection implements ICollection {
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //
                // PROPERTIES
                //
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

                protected var _data:Array;
                private var _overwrite:Boolean;

                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //
                // PUBLIC
                //
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

                /**
                 * Constructor
                 */
                public function ArrayCollection(data:Array=null,overwrite:Boolean=false):void
                {
                        if(data)
                        {
                                _data = data;
                        }
                        else
                        {
                                _data = [];
                        }

                        this.overwrite = overwrite;
                }

                /**
                 * Adds an item to the end of the array
                 */
                public function addItem(item:Object):Boolean
                {
                        _data.push(item);

                        return true;
                }

                /**
                 * Adds an item at a specific index. You cannot overwrite items with this method.
                 *
                 * @param index         The index where the value should be stored.
                 * @param item          The value you want to store
                 * @return                      true if the item was added, and false if not. indexes that are already in use cannot be overwritten with this method.
                 */
                public function addItemAtIndex(index:int,item:Object):Boolean
                {
                        if(!overwrite && _data[index])
                        {
                                return false;
                        }
                        _data[index] = item;

                        return true;
                }

                /**
                 * Get item at a specific index
                 *
                 * @param index         The index of the item to get.
                 *
                 * @return The value found at that index.
                 */
                public function getItemByIndex(index:int):Object
                {
                        return _data[index];
                }

                /**
                 * Gets the first match in the collection based on the value of a specified child property.
                 *
                 * @param childProperty         The property of the child you wish to search.
                 * @param childValue            The value of the child's property.
                 *
                 * @return the result of the specified parameters
                 */
                public function getItemByChildProperty(property:String, propertyValue:*):Object
                {
                        for each(var item:Object in _data)
                        {
								MonsterDebugger.trace(this, "for each in _data");
								if(item[property] == propertyValue)
                                {
                                        return item;
                                }
                        }
                        return null;
                }

                /**
                 * Returns matches of the specified property-value.
                 * Use the getItemByChildProperty if you only want 1 returned value
                 *
                 * @param childProperty         The property of the child you wish to search
                 * @param childValue            The value of the child's property you are looking for
                 *
                 * @return A collection of items that matches the criteria
                 */
                public function getItemsByPropertyValue(property:String, propertyValue:*):ArrayCollection
                {
                        var matches:ArrayCollection = new ArrayCollection();

                        for each(var item:* in _data)
                        {
                                if(item[property] == propertyValue)
                                {
                                        matches.addItem(item);
                                }
                        }
                        return matches;
                }

                /**
                 * Gets the first element in the list. Should work for both integer based keys and String keys
                 *
                 * @return                      Returns the first element in the collection.
                 */
                public function getFirstItem():Object
                {
                        for each(var item:Object in _data)
                        {
                                return item;
                        }
                        return null;
                }

                /**
                 * Gets the last element in the list.
                 *
                 * @return                      Returns the last element in the collection.
                 */
                public function getLastItem():Object
                {
                        var counter:int = 1;
                        for each(var item:Object in _data)
                        {
                                if(counter == length)
                                {
                                        return item;
                                }
                                counter++;
                        }
                        return null;
                }

                /**
                 * Gets a new array from a specific range.
                 */
                public function getCollectionRange(startIndex:int,length:int):ArrayCollection
                {
                        return new ArrayCollection(_data.slice(startIndex,startIndex + length));
                }

                /**
                 * Simply removes the specified item from the collection
                 *
                 * @param item          The actual item stored in this collection.
                 * @return                      Success of removal
                 */
                public function removeItem(item:Object):Boolean
                {
                        var loops:int = _data.length; // optimizes for-loop.
                        for(var i:int; i < loops; i++)
                        {
                                if(_data[i] == item)
                                {
                                        _data.splice(i,1);
                                        return true;
                                }
                        }
                        return false;
                }

                /**
                 * Removes an item by index
                 *
                 * @param index         The index to remove
                 * @return                      Success of removal
                 */
                public function removeItemAtIndex(index:int):Boolean
                {
                        if(Boolean(_data.splice(index,1).length))
                        {
                                return true;
                        }

                        return false;
                }

                /**
                 * Removes an item by specifiying the child property and value.
                 *
                 * @param property                      The property of each item to check.
                 * @param value                         The value to compare each item's property to.
                 * @return                                      Success of the removal.
                 */
                public function removeItemByChildProperty(property:String, value:*):Boolean
                {
                        var loops:int = _data.length; // optimizes for-loop
                        for(var i:int = 0; i < loops; i++)
                        {
                                if(_data[i].hasOwnProperty(property))
                                {
                                        if(_data[i][property] == value)
                                        {
                                                _data.splice(i,1);
                                                return true;
                                        }
                                }
                        }
                        return false;
                }

                /**
                 * Removes all the items in the collection
                 */
                public function removeAllItems():void
                {
                        _data = [];
                }

                /**
                 * Checks if a value exists within a specified index.
                 *
                 * @param index                 The key that is used for storing.
                 * @return                              True or false whether the index holds a value.
                 */
                public function hasItemAtIndex(index:int):Boolean
                {
                        return _data[index];
                }

                /**
                 * Checks if a specified value exists.
                 *
                 * @param item                  The item to look for
                 * @return                              True or false whether the item exists.
                 */
                public function hasItem(item:Object):Boolean
                {
                        var loops:int = _data.length; // optimizes for-loop
                        for(var i:int = 0; i < loops; i++)
                        {
                                if(_data[i] == item)
                                {
                                                return true;
                                }
                        }
                        return false;
                }

                /**
                 * toString
                 */
                public function toString():String
                {
                        var result:String = '';
                        for each(var item:* in _data)
                        {
                                result += item + ', ';
                        }
                        return result.substr(0,result.length - 2); // remove last ,
                }

                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //
                // PRIVATE
                //
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //
                // PROTECTED
                //
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //
                // EVENTHANDLERS
                //
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //
                // GETTERS & SETTERS
                //
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

                /**
                 * read only property
                 */
                public function get data():Array
                {
                        return _data;
                }

                /**
                 * read only property
                 */
                public function get length():int
                {
                        return _data.length;
                }

                public function get overwrite():Boolean
                {
                        return _overwrite;
                }
                public function set overwrite(value:Boolean):void
                {
                        _overwrite = value;
                }
		
	}
}
